package edu.chl.grupp11.aegas.controller.imp;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
import java.util.Observable;

import javax.swing.JButton;

import org.apache.sanselan.ImageReadException;
import org.farng.mp3.TagException;

import edu.chl.grupp11.aegas.controller.AbstractTagHandler;
import edu.chl.grupp11.aegas.controller.ErrorControllerFactory;
import edu.chl.grupp11.aegas.controller.IErrorController;
import edu.chl.grupp11.aegas.controller.ITagController;
import edu.chl.grupp11.aegas.model.AbstractConfig;
import edu.chl.grupp11.aegas.model.AbstractMetaTag;
import edu.chl.grupp11.aegas.model.ConfigFactory;
import edu.chl.grupp11.aegas.view.DeletableTagView;
import edu.chl.grupp11.aegas.view.TagView;

public class TagController extends Observable implements ITagController {
	private static TagController instance = new TagController();

	public static TagController getInstance() {
		return instance;
	}

	private IErrorController errorController = ErrorControllerFactory
			.getErrorController();

	private AbstractConfig config = ConfigFactory.getSharedConfig();

	private ArrayList<TagView> tagViews;

	private ArrayList<AbstractTagHandler> handlers = new ArrayList<AbstractTagHandler>();

	private TagController() {
		tagViews = new ArrayList<TagView>();
		updateHandlers();
	}

	@Override
	public void addTagView(TagView tv) {
		if (tv instanceof DeletableTagView) {
			tv.addPropertyChangeListener("delete",
					new PropertyChangeListener() {
						@Override
						public void propertyChange(PropertyChangeEvent evt) {
							JButton event = (JButton) evt.getSource();
							deleteTagView((TagView) event.getParent());
						}
					});
		}
		if (hasTagView(tv)) {
			return;
		}
		tagViews.add(tv);
	}

	@Override
	public void clearTagViewList() {
		tagViews.clear();
	}

	@Override
	public void deleteTagView(TagView tv) {
		tagViews.remove(tv);
	}

	@Override
	public void editTag(File file, AbstractMetaTag tag, String newValue)
			throws UnsupportedOperationException {
		for (AbstractTagHandler handler : handlers) {
			if (handler.accepts(file)) {
				handler.editTag(file, tag, newValue);
				return;
			}
		}

		errorController.setErrorMessage(null, config.getResourceBundle()
				.getString("error13") + file.getAbsolutePath());
	}

	@Override
	public ArrayList<AbstractMetaTag> extractMetadata(File file) {
		for (AbstractTagHandler handler : handlers) {
			if (handler.accepts(file)) {
				try {
					return handler.extractTags(file);
				} catch (ImageReadException e) {
				} catch (IOException e) {
				} catch (TagException e) {
				}
			}
		}
		errorController.setErrorMessage(null, config.getResourceBundle()
				.getString("error6"));
		return null;
	}

	private ArrayList<AbstractTagHandler> getExtensions() {
		File folder = new File(
				"src/edu/chl/grupp11/aegas/controller/extensions");
		ArrayList<AbstractTagHandler> extensions = new ArrayList<AbstractTagHandler>();
		for (File f : folder.listFiles()) {
			if (f.isFile()) {
				String filename = f.getAbsolutePath();
				ObjectInputStream in = null;
				boolean fail = false;

				try {
					in = new ObjectInputStream(new BufferedInputStream(
							new FileInputStream(filename)));
					AbstractTagHandler handler = (AbstractTagHandler) in
							.readObject();

					extensions.add(handler);
					in.close();
				} catch (ClassCastException ex) {
					fail = true;
				} catch (IOException ex) {
					fail = true;
				} catch (ClassNotFoundException ex) {
					fail = true;
				}

				if (fail) {
					errorController.setErrorMessage(null, config
							.getResourceBundle().getString("error14"));
					fail = false;
				}
			}
		}

		return extensions;
	}

	@Override
	public ArrayList<TagView> getTagViews(File file) {
		for (AbstractTagHandler handler : handlers) {
			if (handler.accepts(file)) {
				return handler.getTagViews(file);
			}
		}
		errorController.setErrorMessage(null, config.getResourceBundle()
				.getString("error6"));
		return null;
	}

	@Override
	public ArrayList<TagView> getVisibleTagViews() {
		return tagViews;
	}

	@Override
	public boolean hasTagView(TagView tv) {
		for (TagView t : tagViews) {
			if (t == tv) {
				return true;
			}
		}
		return false;
	}

	@Override
	public void updateHandlers() {
		handlers.clear();
		// AbstractTagHandler mp3Handler = new MP3Handler();
		AbstractTagHandler imageHandler = new ImageHandler();

		// handlers.add(mp3Handler);
		handlers.add(imageHandler);

		for (AbstractTagHandler handler : getExtensions()) {
			handlers.add(handler);
		}
	}
}
